package com.higgins.eventtracking.client;

import java.util.Date;
import java.util.List;

import com.higgins.eventtracking.client.dto.DynamicTypeDTO;
import com.higgins.eventtracking.client.dto.FinanceStatsDTO;
import com.higgins.eventtracking.client.dto.TrackingEventDTO;
import com.higgins.eventtracking.client.dto.TransactionDTO;
import com.higgins.eventtracking.shared.FieldVerifier;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class FinanceTracking implements EntryPoint {
	/**
	 * The message displayed to the user when the server cannot be reached or
	 * returns an error.
	 */
	private static final String SERVER_ERROR = "An error occurred while "
			+ "attempting to contact the server. Please check your network "
			+ "connection and try again.";

	/**
	 * Create a remote service proxy to talk to the server-side Greeting service.
	 */
	private final FinanceTrackingServiceAsync financeTrackingService = GWT
		.create(FinanceTrackingService.class);
	private final AssetTrackingServiceAsync assetTrackingService = GWT
		.create(AssetTrackingService.class);

	final CheckBox yearlyExpenseCheckBox = new CheckBox();
	
	final Label totalSpentThisWeekLabel = new Label();
	final Label totalSpentThisMonthLabel = new Label();
	final Label forecastSpendThisWeek = new Label();
	final Label forecastSpendThisMonth = new Label();
	final Label averageWeeklySpend = new Label();
	final Label forecastSavingThisMonth = new Label();
	final Label weekNumber = new Label();

	final Label totalSavingsLabel = new Label();
	final Label forecastSavingsAtEndOfNextQuarterLabel = new Label();
	final Label forecastUnemployedSavingsAtEndOfNextQuarterLabel = new Label();
	final Label endOfNextQuarterLabel = new Label();
	
	final Button sendButton = new Button("Add");
	final TextBox nameField = new TextBox();
	final ListBox transactionTypeListBox = new ListBox();
	final TextBox amountTextBox = new TextBox();
	final TextBox descriptionTextBox = new TextBox();
	final Label errorLabel = new Label();
	final DialogBox dialogBox = new DialogBox();
	final Button closeButton = new Button("Close");
	final Label textToServerLabel = new Label();
	final HTML serverResponseLabel = new HTML();


	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		populatePageComponents();
		attachPageComponents();
		
		populateFinanceStatsFields();
		createDialogBox();
		
		createHandlers();
	}
	
	public void populateFinanceStatsFields()	{
		populateYearlyExpenseCheckBox();
		populateTotalSpentThisWeek();
		populateTotalSpentThisMonth();
		populateForecastSpendThisWeek();
		populateForecastSpendThisMonth();
		populateAverageWeeklySpend();
		populateForecastSavingsThisMonth();
		populateWeekNumber();
		
		populateTotalSavings();
		populateForecastForSavingsAtEndOfNextQuarter();
		populateForecastUnemployedForSavingsAtEndOfNextQuarter();
		populateEndOfNextQuarter();
	}
	
	private void populateYearlyExpenseCheckBox()	{
		yearlyExpenseCheckBox.setValue(false);
	}
	
	private void populateTotalSpentThisWeek() throws IllegalArgumentException	{
		try {
			financeTrackingService.retrieveTotalSpentThisWeek(new Date(), true,
					new AsyncCallback<Double>()	{

						@Override
						public void onFailure(Throwable caught) {
							totalSpentThisWeekLabel.setText("FAILURE");
						}

						@Override
						public void onSuccess(Double result) {
							totalSpentThisWeekLabel.setText(convertDoubleToString(result));
						}
					});
		} catch (SecurityAccessDeniedException e) {
			totalSpentThisWeekLabel.setText("FAILURE");
		}
	}
	private void populateTotalSpentThisMonth() throws IllegalArgumentException	{
		try {
			financeTrackingService.retrieveTotalSpentThisMonth(new Date(), true, 
					new AsyncCallback<Double>()	{

						@Override
						public void onFailure(Throwable caught) {
							totalSpentThisMonthLabel.setText("FAILURE");
						}

						@Override
						public void onSuccess(Double result) {
							totalSpentThisMonthLabel.setText(convertDoubleToString(result));
						}
					});
		} catch (SecurityAccessDeniedException e) {
			totalSpentThisMonthLabel.setText("FAILURE");
		}
	}
	private void populateForecastSpendThisWeek() throws IllegalArgumentException	{
		try {
			financeTrackingService.retrieveForecastSpendThisWeek(new Date(), true, 
					new AsyncCallback<Double>()	{

						@Override
						public void onFailure(Throwable caught) {
							forecastSpendThisWeek.setText("FAILURE");
						}

						@Override
						public void onSuccess(Double result) {
							forecastSpendThisWeek.setText(convertDoubleToString(result));
						}
					});
		} catch (SecurityAccessDeniedException e) {
			forecastSpendThisWeek.setText("FAILURE");
		}
	}
	private void populateForecastSpendThisMonth() throws IllegalArgumentException	{
		try {
			financeTrackingService.retrieveForecastSpendThisMonth(new Date(), true, 
					new AsyncCallback<Double>()	{

						@Override
						public void onFailure(Throwable caught) {
							forecastSpendThisMonth.setText("FAILURE");
						}

						@Override
						public void onSuccess(Double result) {
							forecastSpendThisMonth.setText(convertDoubleToString(result));
						}
					});
		} catch (SecurityAccessDeniedException e) {
			forecastSpendThisMonth.setText("FAILURE");
		}
	}
	private void populateAverageWeeklySpend() throws IllegalArgumentException	{
		try {
			financeTrackingService.retrieveAverageWeeklySpend(new Date(), false, 
					new AsyncCallback<Double>()	{

						@Override
						public void onFailure(Throwable caught) {
							averageWeeklySpend.setText("FAILURE");
						}

						@Override
						public void onSuccess(Double result) {
							averageWeeklySpend.setText(convertDoubleToString(result));
						}
					});
		} catch (SecurityAccessDeniedException e) {
			averageWeeklySpend.setText("FAILURE");
		}
	}
	
	private void populateForecastSavingsThisMonth() throws IllegalArgumentException	{
		try {
			financeTrackingService.retrieveForecastSavingsThisMonth(new Date(), true, 
					new AsyncCallback<Double>()	{

						@Override
						public void onFailure(Throwable caught) {
							forecastSavingThisMonth.setText("FAILURE");
						}

						@Override
						public void onSuccess(Double result) {
							forecastSavingThisMonth.setText(convertDoubleToString(result));
						}
					});
		} catch (SecurityAccessDeniedException e) {
			forecastSavingThisMonth.setText("FAILURE");
		}
	}
	
	private void populateWeekNumber() throws IllegalArgumentException	{
		try {
			financeTrackingService.retrieveWeekNumber(new Date(), 
					new AsyncCallback<String>()	{

						@Override
						public void onFailure(Throwable caught) {
							weekNumber.setText("FAILURE");
						}

						@Override
						public void onSuccess(String result) {
							weekNumber.setText(result);
						}
					});
		} catch (SecurityAccessDeniedException e) {
			weekNumber.setText("FAILURE");
		}
	}
	
	/*
	private void populateFinanceStatsFields()	{
		financeTrackingService.retrieveFinanceStats(
			new AsyncCallback<FinanceStatsDTO>()	{

				@Override
				public void onFailure(Throwable caught) {
					totalSpentThisWeekLabel.setText("FAILURE");
				}

				@Override
				public void onSuccess(FinanceStatsDTO result) {
					averageWeeklySpentThisMonthLabel.setText(result.getAverageWeeklySpentThisMonth().toString());
					weekNumberLabel.setText(result.getWeekNumber().toString());
					expectedSavingThisMonthLabel.setText(result.getExpectedSavingThisMonth().toString());
					spentThisMonthLabel.setText(result.getSpentThisMonth().toString());
					totalRemainingThisMonthLabel.setText(result.getTotalRemainingThisMonth().toString());
				}
		});
	}	*/
	private void populateTotalSavings()	{
		assetTrackingService.retrieveTotalAssetAmount(			
				new AsyncCallback<String>()	{

				@Override
				public void onFailure(Throwable caught) {
					totalSavingsLabel.setText("FAILURE");
				}

				@Override
				public void onSuccess(String result) {
					totalSavingsLabel.setText(convertStringDoubleToString(result));
				}
		});

	}
	
	private void populateForecastForSavingsAtEndOfNextQuarter()	{
		assetTrackingService.retrieveForecastedEndOfNextQuarterTotalAssets(true, new Date(), 
				new AsyncCallback<String>() {
					@Override
					public void onFailure(Throwable caught) {
						forecastSavingsAtEndOfNextQuarterLabel.setText("FAILURE");
					}

					@Override
					public void onSuccess(String result) {
						forecastSavingsAtEndOfNextQuarterLabel.setText(convertStringDoubleToString(result));
					}
				});
	}
	
	private void populateForecastUnemployedForSavingsAtEndOfNextQuarter()	{
		assetTrackingService.retrieveForecastedEndOfNextQuarterTotalAssets(false, new Date(), 
				new AsyncCallback<String>() {
					@Override
					public void onFailure(Throwable caught) {
						forecastUnemployedSavingsAtEndOfNextQuarterLabel.setText("FAILURE");
					}

					@Override
					public void onSuccess(String result) {
						forecastUnemployedSavingsAtEndOfNextQuarterLabel.setText(convertStringDoubleToString(result));
					}
				});
	}
	private void populateEndOfNextQuarter()	{
		assetTrackingService.retrieveEndOfNextQuarter(new Date(), 
				new AsyncCallback<String>() {
					@Override
					public void onFailure(Throwable caught) {
						endOfNextQuarterLabel.setText("FAILURE");
					}

					@Override
					public void onSuccess(String result) {
						endOfNextQuarterLabel.setText(result);
					}
				});
	}

	public String convertStringDoubleToString(String inValue)	{
		Double doubleValue = Double.parseDouble(inValue);
		return convertDoubleToString(doubleValue);
	}
	public String convertDoubleToString(Double inValue){
		String stringValue = inValue.toString();
		int positionOfDot = stringValue.indexOf(".");
		int lengthOfNumberText = stringValue.length();
		if ((lengthOfNumberText - positionOfDot) > 3)
			lengthOfNumberText = positionOfDot+3;
		if (positionOfDot>0)
			stringValue = stringValue.substring(0, lengthOfNumberText);
		return stringValue;
	}	
	
	
	private void attachPageComponents()	{
		
		RootPanel.get("transactionTypeList").add(transactionTypeListBox);
		RootPanel.get("amountParamter").add(amountTextBox);
		RootPanel.get("descriptionParmeter").add(descriptionTextBox);
		RootPanel.get("addButtonContainer").add(sendButton);
	
		RootPanel.get("yearlyExpense").add(yearlyExpenseCheckBox);
		
		RootPanel.get("totalSpentThisWeekLabel").add(totalSpentThisWeekLabel);
		RootPanel.get("totalSpentThisMonthLabel").add(totalSpentThisMonthLabel);
		RootPanel.get("forecastSpendThisWeek").add(forecastSpendThisWeek);
		RootPanel.get("forecastSpendThisMonth").add(forecastSpendThisMonth);
		RootPanel.get("averageWeeklySpend").add(averageWeeklySpend);
		RootPanel.get("forecastSavingThisMonth").add(forecastSavingThisMonth);
		RootPanel.get("weekNumber").add(weekNumber);
		
		RootPanel.get("totalSavings").add(totalSavingsLabel);
		RootPanel.get("forecastSavingsAtEndOfNextQuarter").add(forecastSavingsAtEndOfNextQuarterLabel);
		RootPanel.get("forecastUnemployedSavingsAtEndOfNextQuarter").add(forecastUnemployedSavingsAtEndOfNextQuarterLabel);
		RootPanel.get("endOfNextQuarter").add(endOfNextQuarterLabel);
		
	}
	
	private void populateTransactionTypes()	{
		transactionTypeListBox.addItem("------");
//		transactionTypeListBox.addItem("Weekly Shop");
//		transactionTypeListBox.addItem("Breakfast");
//		transactionTypeListBox.addItem("Lunch");		
//		transactionTypeListBox.addItem("Dinner");
//		transactionTypeListBox.addItem("Coffee");
//		transactionTypeListBox.addItem("Date");
//		transactionTypeListBox.addItem("Social");		
//		transactionTypeListBox.addItem("Petrol");		
//		transactionTypeListBox.addItem("Other");		
		try {
			financeTrackingService.retrieveDynamicTypes("TransactionType", new AsyncCallback<List<DynamicTypeDTO>>()  {

				@Override
				public void onFailure(Throwable caught) {
					transactionTypeListBox.addItem("Failed!!!");

				}

				@Override
				public void onSuccess(List<DynamicTypeDTO> result) {
					for (DynamicTypeDTO dto:result)	{
						transactionTypeListBox.addItem(dto.getDynamicType());
					}
					
				} });
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityAccessDeniedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void populatePageComponents()	{
		nameField.setText("GWT User1");
		populateTransactionTypes();
		amountTextBox.setText("0.0");
		descriptionTextBox.setText("");
		sendButton.addStyleName("sendButton");
		nameField.setFocus(true);
		nameField.selectAll();
		yearlyExpenseCheckBox.setValue(false);
	}
	
	private void createDialogBox()	{
		// Create the popup dialog box
		dialogBox.setText("Remote Procedure Call");
		dialogBox.setAnimationEnabled(true);
		// We can set the id of a widget by accessing its Element
		closeButton.getElement().setId("closeButton");
		VerticalPanel dialogVPanel = new VerticalPanel();
		dialogVPanel.addStyleName("dialogVPanel");
		dialogVPanel.add(new HTML("<b>Sending name to the server:</b>"));
		dialogVPanel.add(textToServerLabel);
		dialogVPanel.add(new HTML("<br><b>Server replies:</b>"));
		dialogVPanel.add(serverResponseLabel);
		dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
		dialogVPanel.add(closeButton);
		dialogBox.setWidget(dialogVPanel);

		// Add a handler to close the DialogBox
		closeButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogBox.hide();
				sendButton.setEnabled(true);
				sendButton.setFocus(true);
			}
		});
	}
	
	private void createHandlers()	{
		// Create a handler for the sendButton and nameField
		class MyHandler implements ClickHandler, KeyUpHandler, ChangeHandler {
			/**
			 * Fired when the user clicks on the sendButton.
			 */
			public void onClick(ClickEvent event) {
				sendTrackingEventToServer();
			}

			/**
			 * Fired when the user types in the nameField.
			 */
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
					sendTrackingEventToServer();
				}
			}

			/**
			 * Send the name from the nameField to the server and wait for a response.
			 */
			private void sendTrackingEventToServer() {
				// First, we validate the input.
				errorLabel.setText("");
				String transactionType = transactionTypeListBox.getItemText(transactionTypeListBox.getSelectedIndex());
				Double amount = new Double(amountTextBox.getText());
				String description = descriptionTextBox.getText();
				Boolean yearlyExpense = yearlyExpenseCheckBox.getValue();

				TransactionDTO dto = new TransactionDTO(null, new Date(), transactionType, amount, description, yearlyExpense);
								
				sendButton.setEnabled(false);
				financeTrackingService.insertTransaction(dto,
						new AsyncCallback<String>() {
							public void onFailure(Throwable caught) {
								// Show the RPC error message to the user
								dialogBox.setText("Remote Procedure Call - Failure");
								serverResponseLabel.addStyleName("serverResponseLabelError");
								serverResponseLabel.setHTML(SERVER_ERROR);
								dialogBox.center();
								dialogBox.setPopupPosition(0, 0);
								closeButton.setFocus(true);
							}

							public void onSuccess(String result) {
								dialogBox.setText("Remote Procedure Call");
								serverResponseLabel.removeStyleName("serverResponseLabelError");
								serverResponseLabel.setHTML(result);
								dialogBox.center();
								dialogBox.setPopupPosition(0, 0);
								closeButton.setFocus(true);
								amountTextBox.setText("0.0");
								descriptionTextBox.setText("");
								populateFinanceStatsFields();
							}
						});
			}
			
			@Override
			public void onChange(ChangeEvent event) {
				amountTextBox.setText("0.0");
				descriptionTextBox.setText("");
			}
		}
		
		// Add a handler to send the name to the server
		MyHandler handler = new MyHandler();
		sendButton.addClickHandler(handler);
		nameField.addKeyUpHandler(handler);
		transactionTypeListBox.addChangeHandler(handler);
	}
}
